using System;
using System.Collections.Generic;
using CoreVirtuoso;
using CoreVirtuoso.Config;
using CoreVirtuoso.Descriptions;
using CoreVirtuoso.Helpers;
using VDS.RDF.Query;
using VDS.RDF.Storage;
using VirtuosoDal.Config;
using VirtuosoDal.Helpers;
using VirtuosoDal.Repositories.RdfRepositories.Interfaces.Lgd;

namespace VirtuosoDal.Repositories.RdfRepositories.Lgd
{
   public class LgdContentRepository : ILgdContentRepository
   {
      public List<string> GetNearestObjectsTypes(double westLatitude, double southLongitude,
                                                 double eastLatitude, double northLongitude)
      {
         string geoFilter = GeoHelper.GetFilter(westLatitude, eastLatitude, southLongitude, northLongitude);

         string query = string.Format("prefix rdf:           <http://www.w3.org/1999/02/22-rdf-syntax-ns#> " +
                                      "prefix owl:           <http://www.w3.org/2002/07/owl#> " +
                                      "prefix  rdfs:         <http://www.w3.org/2000/01/rdf-schema#> " +
                                      "prefix events:        <http://www.semanticweb.org/ontologies/2010/1/Events.owl#> " +
                                      "prefix geo:           <http://www.w3.org/2003/01/geo/wgs84_pos#> " +
                                      "prefix linkedgeodata: <http://linkedgeodata.org/vocabulary#> " +
                                      "SELECT DISTINCT ?objectType " +
                                      "WHERE " +
                                      "{{ " +
                                      " ?element a ?objectType . " +
                                      " ?element rdfs:label ?name . " +
                                      " ?element geo:lat ?lat . " +
                                      " ?element geo:long ?long . " +
                                      " FILTER ( {0} ) " +
                                      "}} ", geoFilter);

         SparqlParameterizedString sparqlParameterizedString = new SparqlParameterizedString(query);
         //sparqlParameterizedString.SetUri("@graph", new Uri(Namespaces.LgdContentNamespace));

         using (var sparqlConnector = new SparqlConnector(ConnectionStringsHelper.GetLinkedGeoDataSparqlEndPointUri()))
         {
            sparqlConnector.SkipLocalParsing = true;

            SparqlResultSet sparqlResultSet = QueryHelper.Query(sparqlConnector,
                                                                sparqlParameterizedString.ToString(), null);

            return SparqlResultSetConverter.ToListOfUris(sparqlResultSet);
         }
      }

      public IEnumerable<GeoObjectDescription> GetNearestObjectsByType(string objectTypeUri,
                                                                       double westLatitude, double southLongitude,
                                                                       double eastLatitude, double northLongitude)
      {
         string geoFilter = GeoHelper.GetFilter(westLatitude, eastLatitude, southLongitude, northLongitude);

         string query = string.Format("prefix rdf:           <http://www.w3.org/1999/02/22-rdf-syntax-ns#> " +
                                      "prefix owl:           <http://www.w3.org/2002/07/owl#> " +
                                      "prefix  rdfs:         <http://www.w3.org/2000/01/rdf-schema#> " +
                                      "prefix events:        <http://www.semanticweb.org/ontologies/2010/1/Events.owl#> " +
                                      "prefix geo:           <http://www.w3.org/2003/01/geo/wgs84_pos#> " +
                                      "prefix linkedgeodata: <http://linkedgeodata.org/vocabulary#> " +
                                      "SELECT DISTINCT ?element ?name ?lat ?long " +
                                      "WHERE " +
                                      "{{ " +
                                      " ?element a @objectType. " +
                                      " ?element rdfs:label ?name. " +
                                      " ?element geo:lat ?lat. " +
                                      " ?element geo:long ?long. " +
                                      " FILTER ( {0} ) " +
                                      "}}", geoFilter);

         SparqlParameterizedString sparqlParameterizedString = new SparqlParameterizedString(query);
         //sparqlParameterizedString.SetUri("@graph", new Uri(Namespaces.LgdContentNamespace));
         sparqlParameterizedString.SetUri("@objectType", new Uri(objectTypeUri));

         using (var sparqlConnector = new SparqlConnector(ConnectionStringsHelper.GetLinkedGeoDataSparqlEndPointUri()))
         {
            sparqlConnector.SkipLocalParsing = true;

            SparqlResultSet sparqlResultSet = QueryHelper.Query(sparqlConnector,
                                                                sparqlParameterizedString.ToString(),
                                                                null);
            //ToDo: Ask LGD guys to create RuleSet

            return SparqlResultSetConverter.ToListOfGeoObjectDescription(sparqlResultSet);
         }
      }

      public List<ObjectDescription> GetLgdObjectsDescriptions(List<string> objectsUris)
      {
         if (objectsUris == null || objectsUris.Count == 0)
            return new List<ObjectDescription>();

         string urisEnumerationString = UriEnumerationHelper.GetUriEnumerationString(objectsUris.Count);

         string query = String.Format("prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> " +
                                      "SELECT ?lgdObject ?name " +
                                      "WHERE " +
                                      "{{ " +
                                      "  ?lgdObject rdfs:label ?name . " +
                                      "  FILTER " +
                                      "  ( " +
                                      "    ?lgdObject in ({0})" +
                                      "  ) " +
                                      "}} ", urisEnumerationString);

         SparqlParameterizedString sparqlParameterizedString = new SparqlParameterizedString(query);
         UriEnumerationHelper.FillUriEnumerationStringParameters(sparqlParameterizedString, objectsUris);

         using (var sparqlConnector = new SparqlConnector(ConnectionStringsHelper.GetLinkedGeoDataSparqlEndPointUri()))
         {
            sparqlConnector.SkipLocalParsing = true;

            SparqlResultSet sparqlResultSet = QueryHelper.Query(sparqlConnector,
                                                                sparqlParameterizedString.ToString(), null);

            return SparqlResultSetConverter.ToListOfLgdObjectsDescription(sparqlResultSet);
         }
      }
   }
}